

#include "lib/ring_buff.h"
#include "lib/bit.h"
#include "jxos_public.h"
#include "../PHY/jsnet_phy.h"
#include "dlk_frame.h"
#include "dlk_parameter.h"
#include "dlk_debug_print.h"

/*********************************
the dlk_send_receive is a bridge that connect the DLK layer and PHY layer
it follows the performs of the PHY layer to make sure that msg is successfully sent through the PHY layer
there is a data buffer of sending msg
it can write multiple msg in one time and the dlk_send_receive will send the buffer msg one by one

it can not ensure that the message is received by the other side successfully. 
the handler of receiving is an open interface, the caller need to handle the response
*********************************/

#define DLK_SEND_BUFF_FRAME_MAX		10
#define DLK_SEND_REPEAT_COUNT_MAX	3
#define DLK_SEND_PHY_BUSY_RETRY_MAX	3

//ms
#define DELAY_TIME_WAIT_TX_READY	10	//wait for local side tx ready
#define DELAY_TIME_WAIT_REC_READY	50	//wait for the other side rx ready
#define DELAY_TIME_WAIT_RSP			200	//wait for the other side ack
#define DELAY_TIME_REPEAT			500	//delay time for each repeat
#define DELAY_TIME_SENDING_TIME		50	//delay time for send finish
#define DELAY_TIME_PHY_BUSY_TIME	50	//wait when phy was busy
#define DELAY_TIME_CHECK_PAUSE		50	//check pause flag
/***************************************************************/
//dlk_send

static JXOS_EVENT_HANDLE SEND_EVENT_SEND;
static JXOS_EVENT_HANDLE SEND_EVENT_FINISH;
static swtime_type dlk_send_software_timer_id;

static uint8_t dlk_send_buffer[FRAME_LEN_MAX*DLK_SEND_BUFF_FRAME_MAX];
static RINGBUFF_MGR dlk_send_buffer_mgr;

#define SEND_STATE_IDLE				0
#define SEND_STATE_WAIT_READY		1	//wait the tx hardware ready
#define SEND_STATE_SENDING 			2
#define SEND_STATE_WAIT_RSP			3
static uint8_t dlk_send_state = SEND_STATE_IDLE;

#define DLK_SEND_WAIT_READY_FLAG	0
#define DLK_SEND_WAIT_RSP_FLAG		1
#define DLK_SEND_REPEAT_FLAG		2

static uint8_t repeat_count = 0;
static uint8_t phy_busy_retry_count = 0;
static uint8_t pause_flag = 0;

static void phy_confirm_data_send_callback(uint8_t ok_fail)
{
	if(dlk_send_state == SEND_STATE_SENDING){
		jxos_event_set(SEND_EVENT_FINISH);
	}
}

void dlk_send_stop_repeat(void)
{
    repeat_count = 0;
    dlk_send_state = SEND_STATE_IDLE;
}

uint8_t dlk_send_is_repeatting(void)
{
	if(dlk_send_state == SEND_STATE_IDLE){
		return 0;
	}
	else{
		return 1;
	}
}

void dlk_send_pause(void)
{
	pause_flag = 1;
}

void dlk_send_continue(void)
{
	pause_flag = 0;	
}

uint8_t dlk_send(uint8_t* frame, uint8_t frame_len,
				 uint8_t wait_prepare,	//wait for the other side rx ready, enabled when this send msg is a response to the the other side
				 uint8_t wait_respons,	//wait for the other side ack, enabled when need ack
				 uint8_t repeat)		//enabled when need repeat
{
	uint8_t control_flag = 0;
	if((frame_len+1) <= ringbuff_check_free_space(&dlk_send_buffer_mgr)){
		if(wait_prepare != 0){
			set_bit(control_flag, DLK_SEND_WAIT_READY_FLAG);
		}

		if(wait_respons != 0){
			set_bit(control_flag, DLK_SEND_WAIT_RSP_FLAG);
		}

		if(repeat != 0){
			set_bit(control_flag, DLK_SEND_REPEAT_FLAG);
		}

		ringbuff_write_data(&dlk_send_buffer_mgr, 1, &frame_len);
		ringbuff_write_data(&dlk_send_buffer_mgr, 1, &control_flag);
		ringbuff_write_data(&dlk_send_buffer_mgr, frame_len, frame);
		jxos_event_set(SEND_EVENT_SEND);
		frame_count_add();
		return 1;
	}
	else{
		return 0;
	}
}

static uint8_t dlk_to_phy_buffer[FRAME_LEN_MAX];
static uint8_t dlk_to_phy_buffer_len;
static uint8_t dlk_send_control_flag = 0;
void dlk_send_handler(void)
{
	if(sys_svc_software_timer_check_running(dlk_send_software_timer_id) == 0){
        if(jxos_event_wait(SEND_EVENT_SEND) == 0){
            return;
        }
        else{
            sys_svc_software_timer_set_time(dlk_send_software_timer_id, 1);
            sys_svc_software_timer_restart(dlk_send_software_timer_id);
            return;
        }
	}

    if(sys_svc_software_timer_check_overtime(dlk_send_software_timer_id) == 1){
        sys_svc_software_timer_stop(dlk_send_software_timer_id);
        switch(dlk_send_state){
        case SEND_STATE_IDLE:
			if(pause_flag == 1){
				sys_svc_software_timer_set_time(dlk_send_software_timer_id,
														DELAY_TIME_CHECK_PAUSE);
				sys_svc_software_timer_restart(dlk_send_software_timer_id);
				break;
			}
			if(ringbuff_check_used_space(&dlk_send_buffer_mgr) != 0){
				ringbuff_read_data(&dlk_send_buffer_mgr, 1, &dlk_to_phy_buffer_len);
				ringbuff_read_data(&dlk_send_buffer_mgr, 1, &dlk_send_control_flag);
				if(RINGBUFF_ERROR == ringbuff_read_data
                    (&dlk_send_buffer_mgr, dlk_to_phy_buffer_len, dlk_to_phy_buffer)){
                    ringbuff_reset(&dlk_send_buffer_mgr);
                    break;
                }
				if(get_bit(dlk_send_control_flag, DLK_SEND_REPEAT_FLAG) == 1){
					repeat_count = DLK_SEND_REPEAT_COUNT_MAX;
				}
				else{
					repeat_count = 0;
				}
				/*****************/
				jsnet_phy_request_rx_disable();
				jsnet_phy_request_tx_enable();

				if(get_bit(dlk_send_control_flag, DLK_SEND_WAIT_READY_FLAG) == 1){
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
														(DELAY_TIME_WAIT_TX_READY+DELAY_TIME_WAIT_REC_READY));
				}
				else{
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
														DELAY_TIME_WAIT_TX_READY);
				}
				sys_svc_software_timer_restart(dlk_send_software_timer_id);
				phy_busy_retry_count = DLK_SEND_PHY_BUSY_RETRY_MAX;
				dlk_send_state = SEND_STATE_WAIT_READY;
				/*****************/
			}
			break;

		case SEND_STATE_WAIT_READY:
			if(jsnet_phy_request_check_tx_busy() == 0){
				jsnet_phy_request_data_send(dlk_to_phy_buffer, dlk_to_phy_buffer_len);
				sys_svc_software_timer_set_time(dlk_send_software_timer_id,
													DELAY_TIME_SENDING_TIME);
				sys_svc_software_timer_restart(dlk_send_software_timer_id);
				dlk_send_state = SEND_STATE_SENDING;
			}
			else{
				if(phy_busy_retry_count > 0){
					phy_busy_retry_count--;
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
														DELAY_TIME_PHY_BUSY_TIME);
					sys_svc_software_timer_restart(dlk_send_software_timer_id);
				}
				else{
					//if phy keep busy, reset the phy
					dlk_debug_print_str("phy send busy!");
					jsnet_phy_request_reset();
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
					jsnet_phy_request_rx_enable();
#endif
					jsnet_phy_request_tx_disable();
					repeat_count = 0;
					dlk_send_state = SEND_STATE_IDLE;
				}
			}
			break;

		case SEND_STATE_SENDING:
			if(jxos_event_wait(SEND_EVENT_FINISH) == 1){
				jsnet_phy_request_rx_enable();
				jsnet_phy_request_tx_disable();

				if(get_bit(dlk_send_control_flag, DLK_SEND_WAIT_RSP_FLAG) == 1){
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
														DELAY_TIME_WAIT_RSP);
				}
				else{
					sys_svc_software_timer_set_time(dlk_send_software_timer_id, 1);
				}
				sys_svc_software_timer_restart(dlk_send_software_timer_id);
				dlk_send_state = SEND_STATE_WAIT_RSP;
			}
			else{
				//not get the send finish confirm from phy
				//reset the phy
				dlk_debug_print_str("phy send timeout!");
				jsnet_phy_request_reset();
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				jsnet_phy_request_rx_enable();
#endif
				jsnet_phy_request_tx_disable();
				repeat_count = 0;
				dlk_send_state = SEND_STATE_IDLE;
			}
			break;

		case SEND_STATE_WAIT_RSP:
			if(repeat_count > 0){
				repeat_count--;
				/*****************/
				jsnet_phy_request_rx_disable();
				jsnet_phy_request_tx_enable();

				if(get_bit(dlk_send_control_flag, DLK_SEND_WAIT_READY_FLAG) == 1){
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
													(DELAY_TIME_WAIT_TX_READY+DELAY_TIME_WAIT_REC_READY+DELAY_TIME_REPEAT));
				}
				else{
					sys_svc_software_timer_set_time(dlk_send_software_timer_id,
													DELAY_TIME_WAIT_TX_READY+DELAY_TIME_REPEAT);
				}
				sys_svc_software_timer_restart(dlk_send_software_timer_id);
				phy_busy_retry_count = DLK_SEND_PHY_BUSY_RETRY_MAX;
				dlk_send_state = SEND_STATE_WAIT_READY;
				/*****************/
			}
			else{
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
				jsnet_phy_request_rx_enable();
#endif
				jsnet_phy_request_tx_disable();
				dlk_send_state = SEND_STATE_IDLE;
            }
			break;

		default:
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
			jsnet_phy_request_rx_enable();
#endif
			jsnet_phy_request_tx_disable();
            sys_svc_software_timer_set_time(dlk_send_software_timer_id, 1);
            sys_svc_software_timer_restart(dlk_send_software_timer_id);
			dlk_send_state = SEND_STATE_IDLE;
			break;
        }
    }
}

uint8_t* dlk_send_buff_get(uint8_t* dlk_send_buffer_len)
{
	*dlk_send_buffer_len = dlk_to_phy_buffer_len;
	return &(dlk_to_phy_buffer[0]);
}

void dlk_send_init(void)
{
	jsnet_phy_confirm_data_send = phy_confirm_data_send_callback;

	dlk_send_state = SEND_STATE_IDLE;
	RingBuff(&dlk_send_buffer_mgr, FRAME_LEN_MAX*DLK_SEND_BUFF_FRAME_MAX, dlk_send_buffer);

	SEND_EVENT_SEND = jxos_event_create();
    SEND_EVENT_FINISH = jxos_event_create();
	dlk_send_software_timer_id = sys_svc_software_timer_new();
}

/***************************************************************/
void (*dlk_receive_callbck)(uint8_t* receive_data, uint8_t data_len) = 0;
uint8_t dlk_receive_callbck_register(void (*dlk_receive_callbck)
									 (uint8_t* receive_data, uint8_t data_len))
{
	if(dlk_receive_callbck != 0){
		jsnet_phy_indication_data_receive = dlk_receive_callbck;
		return 1;
	}
	else{
		return 0;
	}
}

void dlk_receive_init(void)
{
#if(JSNET_DLK_DEVICE_TYPE == JSNET_DLK_DEVICE_TYPE_STD_NODE)
		jsnet_phy_request_rx_enable();
#endif
}

/******************************/
uint8_t jsnet_dlk_request_receive_enable(void)
{
	return jsnet_phy_request_rx_enable();
}
uint8_t jsnet_dlk_request_receive_disable(void)
{
	return jsnet_phy_request_rx_disable();
}
